home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Examples / TreeView / TreeView.m < prev   
Encoding:
Text File  |  1995-12-11  |  8.0 KB  |  324 lines

  1. //        Written by Don Yacktman Copyright (c) 1994 by Don Yacktman.
  2. //                Version 1.0.  All rights reserved.
  3. //
  4. //        Modified by Aleksey Sudakov <zander@cnext.crec.mipt.ru>
  5. //        * Dec. 12, 1995 *    Improved scalling for better quality 
  6. //                *.eps, *.tiff generation
  7. //
  8. //        This notice may not be removed from this source code.
  9. //
  10. //    This program is included in the MiscKit by permission from the author
  11. //    and its use is governed by the MiscKit license, found in the file
  12. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  13. //    for a list of all applicable permissions and restrictions.
  14. //    
  15.  
  16. // Thanks to Robert Nicholson <nicholr@gb.swissbank.com> for code to
  17. // draw the lines between buttons as a diagonal+straight bit instead
  18. // of just a diagonal.
  19.  
  20. #import "TreeView.h"
  21. #import "TreeButton.h"
  22. #import "NamedTree.h"
  23. #import "Line.h"
  24.  
  25.  
  26.  
  27. // constants to determine how the buttons are laid out
  28.  
  29. // Button size:
  30. #define BUTTONWIDTH     155.0
  31. #define BUTTONHEIGHT     24.0
  32.  
  33. // Spacing between the buttons:
  34. #define VERTSPACING       8.0
  35. #define HORIZSPACING     40.0
  36.  
  37. #define STRAIGHT_AMOUNT  0.33 // how much straight vs. diagonal line
  38. // The previous behavior can be obtained by making this a zero.
  39.  
  40.  
  41.  
  42.  
  43. @implementation TreeView
  44.  
  45. - initFrame:(const NXRect *)frameRect
  46. {
  47.   [super initFrame:frameRect];
  48.   [self setAutosizing:(unsigned int) (NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE)];
  49.  
  50.   currentButton = nil;
  51.   lineList = nil;
  52.   priorButton = nil;
  53.   [selectedField setNextText: selectedField];
  54.   [selectedField setPreviousText: selectedField];
  55.   currScale  = 1.0;
  56.  
  57.   [self registerForDragging];
  58.   [self setOpaque:YES];
  59.  
  60.   return self;
  61. }
  62.  
  63. - buildTreeFromNode:aNode bottom:(double)ybot
  64.         top:(double)ytop atX:(double)xpos parent:(NXPoint *)pos
  65. {    // add a button representing the node to the View
  66.     // This method is recursive.
  67.     NXRect butFrame = {{(xpos + HORIZSPACING),
  68.             (ybot + (ytop - ybot) / 2 - BUTTONHEIGHT / 2)},
  69.             {BUTTONWIDTH, BUTTONHEIGHT}};
  70.     id newButton = [[[TreeButton alloc] initFrame:&butFrame]
  71.             setTreeNode:aNode];
  72.     id kid, kids = [aNode branches];
  73.     int numBranches = [kids count];
  74.     int i, treeWidth; double diff, accum = ybot;
  75.     NXPoint myCenter = {(NX_X(&butFrame)),
  76.                 (NX_Y(&butFrame) + BUTTONHEIGHT / 2)};
  77.     id newLine;
  78.     id newLine2;
  79.     
  80.     [newButton setTitle:[aNode label]];
  81.     [self addSubview:newButton];
  82.     // line to parent:
  83.     if (pos) {    // NULL if root, so no line
  84.         NXPoint parentRight = { pos->x + BUTTONWIDTH, pos->y };
  85.         NXPoint oldCenter = myCenter;
  86.         newLine = [[Line alloc] init];
  87.         myCenter.x -= STRAIGHT_AMOUNT * (myCenter.x - parentRight.x);
  88.         [newLine setStart:&parentRight end:&myCenter];
  89.         [lineList addObject:newLine];
  90.         newLine2 = [[Line alloc] init];
  91.         [newLine2 setStart:&myCenter end:&oldCenter];
  92.         [lineList addObject:newLine2];
  93.         // make sure the next parent is adjusted.
  94.         myCenter = oldCenter;
  95.         
  96.     }
  97.     // now add any children and the lines to them.
  98.     for (i=numBranches - 1; i >= 0; i--) { // loop isn't entered if no kids.
  99.         kid = [kids objectAt:i];
  100.         treeWidth = [kid width];
  101.         diff = (treeWidth * (BUTTONHEIGHT + VERTSPACING));
  102.         [self buildTreeFromNode:kid bottom:accum
  103.                 top:(accum + diff + VERTSPACING)
  104.                 atX:(xpos + BUTTONWIDTH + HORIZSPACING)
  105.                 parent:&myCenter];
  106.         accum += diff;
  107.     }
  108.     return self;
  109. }
  110.  
  111. - attachTree:aTree
  112. {
  113.     int treeWidth = [aTree width];
  114.     int treeDepth = [aTree depth];
  115.     double height = (treeWidth * (BUTTONHEIGHT + VERTSPACING) + VERTSPACING);
  116.     double width  = (treeDepth * (BUTTONWIDTH + HORIZSPACING) + HORIZSPACING);
  117.     
  118.     treeRoot = aTree;
  119.     if (lineList) [[lineList freeObjects] free];
  120.     lineList = [[List alloc] init];
  121.     // resize the View to accomodate the Buttons
  122.     [self sizeTo:width :height];
  123.     [self buildTreeFromNode:aTree bottom:0.0 top:height atX:0.0 parent:NULL];
  124.  
  125.     return self;
  126. }
  127.  
  128. - drawSelf:(NXRect *)rects :(int)rectCount      // standard rendering method
  129. {
  130.     int i;
  131.     NXColor color = [[self window] backgroundColor];
  132.  
  133.     NXRectClip(rects);    // clipping will reduce rendering time a bit
  134.     // and is needed to keep lines from rendering outside the drawing area
  135.     
  136.     if (NXEqualColor(color, NX_COLORLTGRAY))
  137.        color = NX_COLORDKGRAY;
  138.  
  139.     // PSsetgray(NX_DKGRAY);
  140.     NXSetColor(color);
  141.     NXRectFill(&bounds);
  142.     // PSsetgray(NX_BLACK);
  143.     NXSetColor(NX_COLORBLACK);
  144.     PSsetlinewidth(2.0);
  145.  
  146.     for (i=0; i<[lineList count]; i++) // draw any lines in drawing area
  147.         [[lineList objectAt:i] renderIfInRect:rects];
  148.     for (i=0; i<[[self subviews] count]; i++) // redraw needed buttons
  149.         [[[self subviews] objectAt:i] display:rects :rectCount];
  150.         
  151.     return self;
  152. }
  153.  
  154. - scale:sender
  155. {
  156.   id popUp = [sender window];
  157.   short index = [popUp indexOfItem:[popUp selectedItem]];
  158.   //                   25%   50%  75%  100%  125%  150%  200%  SizeToFit
  159.   //                   0     1      2     3     4     5     6    7
  160.   float factors[] = {0.25,  0.50, 0.75,  1.0, 1.25, 1.50, 2.0, 0.20};
  161.   NXPoint center;
  162.   NXCoord scale = factors[index];
  163.  
  164.   // Initialize width and height bounds when view is not scaled.
  165.   if (currScale == 1.0)
  166.     {
  167.       origWidth = NX_WIDTH(&bounds);
  168.       origHeight = NX_HEIGHT(&bounds);
  169.     }
  170.  
  171.   // Remember the center to we can reset it after the scaling.
  172.   center.x = NX_X(&bounds) + NX_WIDTH(&bounds) / 2;
  173.   center.y = NX_Y(&bounds) + NX_HEIGHT(&bounds) / 2;
  174.  
  175.   // Scale the view to its new size
  176.   if (index == 3) // 100% (Normal Size)
  177.     {
  178.      [self sizeTo:origWidth :origHeight];
  179.      [self setDrawSize:origWidth :origHeight];
  180.      currScale  = 1.0;
  181.     }
  182.   else
  183.     {
  184.       currScale *= scale;
  185.       [self sizeTo:origWidth * currScale
  186.                        :origHeight * currScale];
  187.       [self setDrawSize:origWidth / currScale
  188.                        :origHeight / currScale];
  189.     }
  190.  
  191.   // Reset the center point
  192.   [self setDrawOrigin:center.x - NX_WIDTH(&bounds) / 2
  193.               :center.y - NX_HEIGHT(&bounds) / 2];
  194.  
  195.   // Ensure that selected button, if any, is visible.
  196.   [self displayBut:currentButton];
  197.  
  198.   [self update];
  199.  
  200.   return self;
  201. }
  202.  
  203. - setCurrentButton:but
  204. {
  205.   if (but)
  206.     {
  207.       priorButton = currentButton;
  208.       if (priorButton)
  209.     {
  210.       [priorButton setType:NX_MOMENTARYPUSH];
  211.       [priorButton setState:0];
  212.     }
  213.       currentButton = but;
  214.       [currentButton setType:NX_ONOFF]; [currentButton setState:1];
  215.       // [selectedField setStringValueNoCopy: [but title]];
  216.     }
  217.   return but;
  218. }
  219.  
  220. - setCurrButtonByName:sender
  221. {
  222.   id currBut = [self getButByName:[sender stringValue]];
  223.  
  224.   [self displayBut:[self setCurrentButton:currBut]];
  225.   [treeRoot act:currBut];
  226.   return currBut;
  227. }
  228.  
  229. - getButByName:(const char*)name
  230. {
  231.   id butList = [self subviews];
  232.   id but = nil;
  233.   id currBut = nil;
  234.   int i = 0;
  235.  
  236.   while (!currBut && (but = [butList objectAt:i++]))
  237.     {
  238.       if (!strcmp([but title], name))
  239.     currBut = but;
  240.     }
  241.   return currBut;
  242. }
  243.  
  244. - displayButByName:sender
  245. {
  246.   id but = [self getButByName:[sender stringValue]];
  247.  
  248.   if (but)
  249.     [self displayBut:but];
  250.   return but;
  251. }
  252.  
  253. - displayBut:but
  254. {
  255.   NXRect butRect;
  256.  
  257.   if (but)
  258.     {
  259.       [[but getBounds:&butRect] convertRectToSuperview:&butRect];
  260.       [self scrollRectToVisible:&butRect];
  261.     }
  262.   return self;
  263. }
  264.  
  265. @end
  266.  
  267.  
  268.  
  269. // Color dragging support
  270.  
  271. BOOL includesType(const NXAtom *types, NXAtom type)
  272. {
  273.     if (types)
  274.       while (*types)
  275.     if (*types++ == type)
  276.       return YES;
  277.     return NO;
  278. }
  279.  
  280. @implementation TreeView(Drag)
  281.  
  282. - registerForDragging
  283. {
  284.  [self registerForDraggedTypes:&NXColorPboardType count:1];
  285.  return self;
  286. }
  287.  
  288. - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
  289. {
  290. //  NXDragOperation sourceMask = [sender draggingSourceOperationMask];
  291.   Pasteboard *pboard = [sender draggingPasteboard];
  292.  
  293.   return ((includesType([pboard types], NXColorPboardType))
  294.        ? NX_DragOperationGeneric : NX_DragOperationNone);
  295. }
  296.  
  297. - (BOOL)prepareForDragOperation:(id <NXDraggingInfo>)sender
  298. {
  299.   return YES;
  300. }
  301.  
  302. - (BOOL)performDragOperation:(id <NXDraggingInfo>)sender
  303. {
  304.     Pasteboard *pboard = [sender draggingPasteboard];
  305.  
  306.     if (includesType([pboard types], NXColorPboardType))
  307.       {
  308.     NXColor color = NXReadColorFromPasteboard(pboard);
  309.     [[self window] setBackgroundColor:color];
  310.     [self display];  // reflect color change
  311.     return YES;
  312.       }
  313.     else
  314.       return NO;
  315. }
  316.  
  317. - concludeDragOperation:(id <NXDraggingInfo>)sender
  318. {
  319.   // Return value ignored.
  320.   return nil;
  321. }
  322.  
  323. @end
  324.